import numpy as np


def count_PL(line, point):
    a = line[1] - line[3]
    b = line[2] - line[0]
    c = line[0] * line[3] - line[2] * line[1]
    PL = abs(a * point[0] + b * point[1] + c) / ((a ** 2 + b ** 2) ** 0.5)
    return PL


def count_Phasor_L(point1, point2):
    return ((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2) ** 0.5


def count_L(line):
    return ((line[0] - line[2]) ** 2 + (line[1] - line[3]) ** 2) ** 0.5


# 求内积
def count_Inner_product(line, point):
    AB = np.array([point[0] - line[0], point[1] - line[1]])
    AC = np.array([line[2] - line[0], line[3] - line[1]])
    CA = np.array([line[0] - line[2], line[1] - line[3]])
    CB = np.array([point[0] - line[2], point[1] - line[3]])
    return [np.dot(AB, AC), np.dot(CA, CB)]


def find_node(line1, line2):
    x1, y1, x2, y2 = line1[:4]
    x3, y3, x4, y4 = line2[:4]
    try:
        x = ((x3 - x4) * ((y1 - y2) * x1 - (x1 - x2) * y1) - (x1 - x2) * ((y3 - y4) * x3 - (x3 - x4) * y3)) / (
                (y1 - y2) * (x3 - x4) - (y3 - y4) * (x1 - x2))
        y = ((y3 - y4) * ((y1 - y2) * x1 - (x1 - x2) * y1) - (y1 - y2) * ((y3 - y4) * x3 - (x3 - x4) * y3)) / (
                (y1 - y2) * (x3 - x4) - (y3 - y4) * (x1 - x2))
    except ZeroDivisionError:
        return 0
    else:
        if count_Phasor_L([x, y], line1[:2]) < count_L(line1) and \
                count_Phasor_L([x, y], line1[2:4]) < count_L(line1) and \
                count_Phasor_L([x, y], line2[:2]) < count_L(line2) and \
                count_Phasor_L([x, y], line2[2:4]) < count_L(line2):
            return [x, y]
        else:
            return 0


def gen_allpoints(lines_result):
    allpoints = []
    for i in lines_result:
        allpoints.append([i[0], i[1]])
        allpoints.append([i[2], i[3]])
    for i in range(len(lines_result) - 1):
        for j in range(i + 1, len(lines_result)):
            if find_node(lines_result[i], lines_result[j]) != 0:
                allpoints.append(find_node(lines_result[i], lines_result[j]))
    return allpoints


def judge_box_lines(temp_box, x_box, y_box, lines_results):
    temp_list = []
    for i in range(len(temp_box)):
        x1 = temp_box[i][0] - x_box[i] / 2
        x2 = temp_box[i][0] + x_box[i] / 2
        y1 = temp_box[i][1] - y_box[i] / 2
        y2 = temp_box[i][1] + y_box[i] / 2
        line1_x = [x1, y1, x2, y1]
        line1_y = [x1, y1, x1, y2]
        line2_x = [x1, y2, x2, y2]
        line2_y = [x2, y1, x2, y2]
        for j in range(len(lines_results)):
            # 利用判断两线段之间是否存在交点的方法来判断框框是否覆盖线段
            if find_node(line1_x, lines_results[j]) != 0 \
                    or find_node(line1_y, lines_results[j]) != 0 \
                    or find_node(line2_x, lines_results[j]) != 0 \
                    or find_node(line2_y, lines_results[j]) != 0:
                if i not in temp_list:
                    temp_list.append(i)
    return temp_list


def fix_tex_point_site(allpoints, temp_box, L, tem=17.5):
    # 找最近的点
    for i in range(len(temp_box)):
        min_l = tem
        target_point = []
        for j in range(len(allpoints)):
            CL = count_Phasor_L(temp_box[i], allpoints[j])
            if CL < min_l:
                min_l = CL
                target_point = allpoints[j]
        if min_l == tem:
            continue
        else:
            temp_Phasor = np.array([temp_box[i][0] - target_point[0], temp_box[i][1] - target_point[1]])
            ratio = L / min_l
            new_point = (ratio * temp_Phasor + target_point).tolist()
            temp_box[i] = new_point
    return temp_box


def fix_tex_line_site(temp_box, lines_results, L, tem=17.5):
    box_copy = temp_box.copy()
    # 找最近的线段
    for i in range(len(temp_box)):
        min_l = tem
        j_index = 0
        for j in range(len(lines_results)):
            if count_PL(lines_results[j], temp_box[i]) < min_l:
                if count_Inner_product(lines_results[j], temp_box[i])[0] > 0 \
                        and count_Inner_product(lines_results[j], temp_box[i])[1] > 0:
                    min_l = count_PL(lines_results[j], temp_box[i])
                    j_index = lines_results[j]
        if min_l == tem:
            continue
        else:
            AB_hat = ((count_Phasor_L(j_index, temp_box[i])) ** 2 - (count_PL(j_index, temp_box[i])) ** 2) ** 0.5
            ratio = AB_hat / count_L(j_index)
            AC = np.array([j_index[2] - j_index[0], j_index[3] - j_index[1]])
            A = np.array([j_index[0], j_index[1]])
            p1 = (ratio * AC + A).tolist()
            temp_Phasor = np.array([temp_box[i][0] - p1[0], temp_box[i][1] - p1[1]])
            ratio2 = L / count_Phasor_L(p1, temp_box[i])
            box_copy[i] = temp_Phasor * ratio2 + p1
    return box_copy


# 主函数调用
def fix_tex_site(text_bboxes_processed, lines_results, L):
    temp_box = []
    x_box = []
    y_box = []

    for i in text_bboxes_processed:
        # 记录框框的边长，求中心点
        x_loss = i[2] - i[0]
        y_loss = i[3] - i[1]
        x_box.append(x_loss)
        y_box.append(y_loss)
        temp_box.append([(i[0] + i[2]) / 2, (i[1] + i[3]) / 2])

    allpoints = gen_allpoints(lines_results)  # 生成端点与线段交点的集合
    temp_box = fix_tex_point_site(allpoints, temp_box, L)
    temp_box = fix_tex_line_site(temp_box, lines_results, L)

    # 判断修正后的框框有没有覆盖线段，有则还原该框框
    temp_list = judge_box_lines(temp_box, x_box, y_box, lines_results)
    # for i in temp_list:
    #     temp_box[i] = [(text_bboxes_processed[i][0] + text_bboxes_processed[i][2]) / 2,
    #                    (text_bboxes_processed[i][1] + text_bboxes_processed[i][3]) / 2]

    # 根据中心点求框框的左下角坐标
    for i in range(len(text_bboxes_processed)):

        if i in temp_list:
            print('&'*100)
            temp_box[i] = [text_bboxes_processed[i][0], text_bboxes_processed[i][3]]
        else:
            temp_box[i][0] -= 6
            temp_box[i][1] += 6

    return temp_box

